package com.lagou.edu.listener;

import com.lagou.edu.factory.BeanFactory;
import com.lagou.edu.factory.ProxyFactory;
import com.lagou.edu.utils.GetBeanByType;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author wuyancheng
 */
public class CreateBean {

    private static Map<String, Object> earlyObjects = new HashMap<>();

    public void createBeans(Map<String, BeanDefinition> beanDefinitionMap) throws Exception {
        //优先注册代理，以便于后续对需要事务管理对对象进行增强处理
        BeanDefinition proxyFactory = beanDefinitionMap.get(ProxyFactory.class.getName());
        doCreateBean(proxyFactory,beanDefinitionMap);

        for(Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()){
            if(BeanFactory.getBean(entry.getValue().getAlias()) == null){
                doCreateBean(entry.getValue(), beanDefinitionMap);
            }
        }
    }

    private Object doCreateBean(BeanDefinition  beanDefinition, Map<String, BeanDefinition> beanDefinitionMap) throws Exception {
        Class<?> aClass = Class.forName(beanDefinition.getBeanClassName());
        Object object = aClass.newInstance();
        //判断是否需要属性填充
        if(!beanDefinition.getPropertyMap().isEmpty()){
            //如果需要，则提早暴露自己
            earlyObjects.put(beanDefinition.getAlias(), object);
            for(Map.Entry<String, String> property : beanDefinition.getPropertyMap().entrySet()){
                //先尝试从创建成功的缓存池中获取对象
                Object singletonObject = BeanFactory.getObjects(property.getValue());
                Class propertyClass = null;
                if(singletonObject == null){
                    //未获取到，从早期暴露的缓存池中获取
                    singletonObject = GetBeanByType.doGetBeanByType(earlyObjects, property.getValue());
                    if(singletonObject == null){
                        //早期缓存池也没有，进行创建
                        BeanDefinition propertyBeanDefinition = GetBeanByType.doGetBeanDefinition(beanDefinitionMap,
                                property.getValue());
                        singletonObject = doCreateBean(propertyBeanDefinition,beanDefinitionMap);
                        propertyClass = Class.forName(property.getValue());
                    }
                } else {
                    propertyClass = singletonObject.getClass();
                }

                Method method = object.getClass().getMethod("set" + property.getKey(),propertyClass);
                method.invoke(object, singletonObject);

                //如果需要进行事务增强，生成代理对象
                if(beanDefinition.isTransactional()){
                    ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
                    object = doProxyObject(object,proxyFactory);
                }
            }

            //移除早期对象
            earlyObjects.remove(beanDefinition.getAlias(), object);
            //加入beanFactory的缓存池
            BeanFactory.setBean(beanDefinition.getAlias(), object);
        } else {
            BeanFactory.setBean(beanDefinition.getAlias(), object);
        }
        return object;
    }

    /**
     * 生成事务代理对象
     * @param object
     * @param proxyFactory
     * @return
     */
    public Object doProxyObject(Object object, ProxyFactory proxyFactory){
        if(object.getClass().getInterfaces() != null){
            object = proxyFactory.getJdkProxy(object);
        } else {
            object = proxyFactory.getCglibProxy(object);
        }
        return object;
    }

}
